package controllers

import (
	"encoding/base64"
	"errors"
	"fmt"
	"html"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"sync"

	"devOpsApi/base"
	"devOpsApi/common/util"
	"devOpsApi/config/ymlgo"
	"devOpsApi/middleware"
	"devOpsApi/model"

	"github.com/kataras/iris"
	"github.com/xanzy/go-gitlab"
)

type GitController struct {
	base.BController
}

//获取仓库账号信息
func (c *GitController) GetPublicRepoAccount() {
	uid := int(middleware.GetTokenUId(c.Ctx))
	userOauthModel := model.NewUserOauth()
	userOauth, err := userOauthModel.One(uint(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	config := ymlgo.NewConfigSysBase()
	userOauth.GitServer = config.GitLabServer
	c.OutDataJson(userOauth, iris.StatusOK, "success")
}

//修改仓库账号信息
func (c *GitController) PostRepoAccount() {
	gitLabUser := c.Ctx.PostValueDefault("gitLabUser", "")
	if gitLabUser == "" {
		c.OutDataJson("", iris.StatusBadRequest, "gitLabUser is empty")
		return
	}
	gitLabPwd := c.Ctx.PostValueDefault("gitLabPwd", "")
	if gitLabPwd == "" {
		c.OutDataJson("", iris.StatusBadRequest, "gitLabPwd is empty")
		return
	}
	config := ymlgo.NewConfigSysBase()
	git, err := gitlab.NewBasicAuthClient(
		gitLabUser,
		gitLabPwd,
		gitlab.WithBaseURL(config.GitLabServer),
	)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "gitLab 链接验证失败 :"+err.Error())
		return
	}
	gitUser, _, err := git.Users.CurrentUser()
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "验证失败 :"+err.Error())
		return
	}
	uid := int(middleware.GetTokenUId(c.Ctx))
	userOauthModel := model.NewUserOauth()
	userOauth, err := userOauthModel.One(uint(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	userOauth.GitLabUser = gitLabUser
	userOauth.GitLabPwd = gitLabPwd
	userOauth.GitLabUserId = uint(gitUser.ID)
	err = userOauth.Update()
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	userOauth.GitServer = config.GitLabServer
	c.OutDataJson(userOauth, iris.StatusOK, "success")
}

//todo 开放平台定制化openid搜索
func (c *GitController) GetListOpenIdBy(openid string) {
	uid := uint(middleware.GetTokenUId(c.Ctx))
	PipelineObj := model.NewPipeline()
	pipeline, err := PipelineObj.DetailByName(uid, openid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	if pipeline.CustomGitUrl != "" {
		//gitee github gitlab第三方跳转
		targetUrl := pipeline.CustomGitUrl
		oauthSet := false
		customGitUrlFormat, err := url.Parse(pipeline.CustomGitUrl)
		if err != nil {
			c.OutDataJson("", iris.StatusBadRequest, err.Error())
			return
		}
		if customGitUrlFormat.User.Username() != "" {
			targetUrl = customGitUrlFormat.Scheme + "://" + customGitUrlFormat.Host + customGitUrlFormat.Path
			oauthSet = true
		}
		c.OutDataJson(iris.Map{"targetUrl": targetUrl, "oauthSet": oauthSet, "jumpUrl": true}, iris.StatusOK, "success")
		return
	}

	//取链接仓库中的账号密码
	//gitModel, err := model.NewUserGitlab(int(uid), pipeline.CustomGitUrl)
	gitModel, err := model.NewUserGitlab(int(pipeline.Uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	project, _, err := gitModel.Client.Projects.GetProject(int(pipeline.Pid), &gitlab.GetProjectOptions{})
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	CurrentUser, _, err := gitModel.Client.Users.CurrentUser()
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	longPath := gitModel.Client.BaseURL().Scheme + "://" + gitModel.Client.BaseURL().Host + "/" + CurrentUser.Username + "/"
	list := []*gitlab.Project{project}
	c.OutDataJson(iris.Map{"jumpUrl": false, "list": list, "longPath": longPath, "total": 1, "pages": 1, "currentPage": 1}, iris.StatusOK, "success")
	return
}

// git仓库列表
func (c *GitController) GetList() {
	// 系统本身仓库
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	page, err := strconv.Atoi(c.Ctx.URLParam("page"))
	if err != nil || page < 1 {
		page = 1
	}
	pageSize, err := strconv.Atoi(c.Ctx.URLParam("pageSize"))
	if err != nil || pageSize < 1 {
		pageSize = 20
	}
	k := c.Ctx.URLParamDefault("k", "")
	list, total, pages := gitModel.List(uint(page), uint(pageSize), k)
	CurrentUser, _, err := gitModel.Client.Users.CurrentUser()
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	longPath := gitModel.Client.BaseURL().Scheme + "://" + gitModel.Client.BaseURL().Host + "/" + CurrentUser.Username + "/"
	c.OutDataJson(iris.Map{"list": list, "longPath": longPath, "total": total, "pages": pages, "currentPage": page}, iris.StatusOK, "success")
	return
}

// 创建仓库
func (c *GitController) PostCreateRepo() {
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	var option gitlab.CreateProjectOptions
	if err := c.Ctx.ReadForm(&option); err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	project, _, err := gitModel.Client.Projects.CreateProject(&option)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	if project.DefaultBranch == "" {
		option := &gitlab.CreateFileOptions{
			Branch:        gitlab.String("master"),
			Content:       gitlab.String("自动初始化README.md"),
			CommitMessage: gitlab.String("自动初始化README.md"),
		}
		_, _, _ = gitModel.Client.RepositoryFiles.CreateFile(project.ID, "README.md", option)
	}

	c.OutDataJson("", iris.StatusOK, "success")
	return
}

// 导入仓库
func (c *GitController) PostImportRepo() {
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	var option gitlab.CreateProjectOptions
	if err := c.Ctx.ReadForm(&option); err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	ImportURLParse, _ := url.Parse(*option.ImportURL)
	option.ImportURL = gitlab.String(ImportURLParse.String())
	_, _, err = gitModel.Client.Projects.CreateProject(&option)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	c.OutDataJson("", iris.StatusOK, "success")
	return
}

// 仓库删除
func (c *GitController) PostDelRepo() {
	id := c.Ctx.PostValueIntDefault("id", 0)
	if id == 0 {
		c.OutDataJson("", iris.StatusBadRequest, "参数丢失!")
		return
	}
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	_, err = gitModel.Client.Projects.DeleteProject(id)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	c.OutDataJson("", iris.StatusOK, "success")
	return
}

/*
代码文件列表
ProjectId 仓库ID
ref 分支
path 目录路径
/10/master/pages
*/
func (c *GitController) GetCodeBy(ProjectId int, ref, path string) {
	isIndex := false
	isFile := false
	if path == "root" {
		path = ""
		isIndex = true
	}
	ref = strings.Replace(ref, "--", "/", -1)
	formatPath := strings.Replace(path, "&", "/", -1)
	uid := int(middleware.GetTokenUId(c.Ctx))

	gitModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	TreeNodes := gitModel.AllFileList(ProjectId, ref, formatPath)

	// 文件，目录列表
	var ModelTreeNode []model.TreeNode
	var wg sync.WaitGroup
	var lock sync.RWMutex
	for _, v := range TreeNodes {
		wg.Add(1)
		go func(data gitlab.TreeNode, path string) {
			var _TreeNode model.TreeNode
			ListCommitsOptions := &gitlab.ListCommitsOptions{
				ListOptions: gitlab.ListOptions{
					Page:    1,
					PerPage: 1,
				},
				Path: gitlab.String(data.Path),
			}
			Commits, _, _ := gitModel.Client.Commits.ListCommits(ProjectId, ListCommitsOptions)

			// Commits := gitModel.AllCommitsList(ProjectId, ref, data.Path)
			if len(Commits) > 0 {
				_TreeNode.CommitTitle = Commits[0].Title
				_TreeNode.CommitCreateTime = Commits[0].CreatedAt
			}
			_TreeNode.ID = data.ID
			_TreeNode.Path = data.Path
			_TreeNode.Name = data.Name
			_TreeNode.Type = data.Type
			_TreeNode.Mode = data.Mode
			lock.Lock()
			ModelTreeNode = append(ModelTreeNode, _TreeNode)
			lock.Unlock()
			wg.Done()
		}(v, formatPath)
	}

	// 打开的文件信息
	fileInfo := iris.Map{}
	if strings.Index(path, ".") != -1 {
		isFile = true
		wg.Add(1)
		go func() {
			FileOptions := &gitlab.GetFileOptions{
				Ref: gitlab.String(ref),
			}
			file, _, _ := gitModel.Client.RepositoryFiles.GetFile(ProjectId, formatPath, FileOptions)
			if file.Content == "" {
				return
			}
			fileByte, err := base64.StdEncoding.DecodeString(file.Content)
			if err != nil {
				return
			}
			fileInfo = iris.Map{
				"content":  string(fileByte),
				"FileName": file.FileName,
				"FileSize": file.Size,
				"FilePath": file.FilePath,
			}
			wg.Done()
		}()
	}

	// readme信息
	readme := ""
	if isIndex == true {
		wg.Add(1)
		go func() {
			FileOptions := &gitlab.GetFileOptions{
				Ref: gitlab.String(ref),
			}
			file, _, _ := gitModel.Client.RepositoryFiles.GetFile(ProjectId, "README.md", FileOptions)
			if file == nil {
				readme = ""
			} else {
				fileByte, _ := base64.StdEncoding.DecodeString(file.Content)
				readme = string(fileByte)
			}
			wg.Done()
		}()
	}

	// top commits
	var TopCommits []*gitlab.Commit
	go func() {
		wg.Add(1)
		ListCommitsOptions := &gitlab.ListCommitsOptions{
			ListOptions: gitlab.ListOptions{
				Page:    1,
				PerPage: 1,
			},
			Path: gitlab.String(path),
		}
		TopCommits, _, _ = gitModel.Client.Commits.ListCommits(ProjectId, ListCommitsOptions)
		wg.Done()
	}()
	// 当前git用户信息
	gitUser := &gitlab.User{}
	go func() {
		wg.Add(1)
		gitUser, _, _ = gitModel.Client.Users.CurrentUser()
		wg.Done()
	}()

	// 当前分支
	var Branches []*gitlab.Branch
	go func() {
		wg.Add(1)
		BranchesOptions := &gitlab.ListBranchesOptions{
			ListOptions: gitlab.ListOptions{
				Page:    1,
				PerPage: 100,
			},
		}
		Branches, _, _ = gitModel.Client.Branches.ListBranches(ProjectId, BranchesOptions)
		wg.Done()
	}()
	// tag标签
	var Tags []*gitlab.Tag
	go func() {
		wg.Add(1)
		ListTagsOptions := &gitlab.ListTagsOptions{
			ListOptions: gitlab.ListOptions{
				Page:    1,
				PerPage: 100,
			},
		}
		Tags, _, _ = gitModel.Client.Tags.ListTags(ProjectId, ListTagsOptions)
		wg.Done()
	}()
	// 当前仓库信息
	Project := &gitlab.Project{}
	go func() {
		wg.Add(1)
		ProjectOptions := &gitlab.GetProjectOptions{
			Statistics:           gitlab.Bool(true),
			License:              gitlab.Bool(true),
			WithCustomAttributes: gitlab.Bool(true),
		}
		Project, _, _ = gitModel.Client.Projects.GetProject(ProjectId, ProjectOptions)
		wg.Done()
	}()

	// 当前用户git账号密码
	UserOauth := model.UserOauth{}
	go func() {
		wg.Add(1)
		UserOauthModel := model.NewUserOauth()
		UserOauth, _ = UserOauthModel.One(uint(uid))
		wg.Done()
	}()

	wg.Wait()

	if Project == nil {
		c.OutDataJson("", iris.StatusBadRequest, "项目未找到")
		return
	}

	sort.SliceStable(ModelTreeNode, func(i, j int) bool {
		return ModelTreeNode[i].Name < ModelTreeNode[j].Name
	})

	HTTPURLToRepo, _ := url.Parse(Project.HTTPURLToRepo)
	gitCloneUrl := "git clone " + HTTPURLToRepo.Scheme + "://" + url.QueryEscape(UserOauth.GitLabUser) + ":" + UserOauth.GitLabPwd + "@" + HTTPURLToRepo.Host + HTTPURLToRepo.Path
	rs := iris.Map{
		"list":        ModelTreeNode,
		"nowbranche":  ref,
		"ProjectId":   ProjectId,
		"nowpath":     path,
		"isIndex":     isIndex,
		"isFiles":     isFile,
		"fileInfo":    fileInfo,
		"readme":      readme,
		"Project":     Project,
		"gitUser":     gitUser,
		"branches":    Branches,
		"UserOauth":   UserOauth,
		"gitCloneUrl": gitCloneUrl,
		"tagNum":      len(Tags),
	}
	if len(TopCommits) > 0 {
		rs["TopCommits"] = TopCommits[0]
	} else {
		rs["TopCommits"] = gitlab.Commit{}
	}
	c.OutDataJson(rs, iris.StatusOK, "success")
}

// 公共git仓库列表
func (c *GitController) GetPublicList() {
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	list := gitModel.AllRepoList()
	c.OutDataJson(list, iris.StatusOK, "success")
	return
}

// 公共git仓库分支列表
func (c *GitController) GetPublicBranchesBy(pid int) {
	_keywords := c.Ctx.URLParamDefault("k", "")
	gitModel := model.NewGitlab()
	Branches := gitModel.GetBranches(pid, _keywords)
	c.OutDataJson(Branches, iris.StatusOK, "success")
	return
}

// 公共git仓库分支列表
//https://gitee.com/yanchangyou/aviatorscript-ideaplugin.git
//curl -X GET --header 'Content-Type: application/json;charset=UTF-8' 'https://gitee.com/api/v5/repos/cuijun/godht/branches?access_token=9aca6f693f2e595c177ccd542d1270cd'
//https://github.com/imroc/req.git
func (c *GitController) PostPublicCustomBranches() {
	_url := c.Ctx.PostValueDefault("url", "")
	_keywords := c.Ctx.PostValueDefault("k", "")
	if _url == "" {
		c.OutDataJson("", iris.StatusBadRequest, "链接不存在")
		return
	}

	_urlParse, err := url.Parse(_url)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	switch _urlParse.Host {
	case "gitee.com":
		gitee, err := model.NewGitee(_url)
		if err != nil {
			c.OutDataJson("", iris.StatusBadRequest, err.Error())
			return
		}
		reposId := gitee.GetReposId()
		if reposId == 0 {
			c.OutDataJson("", iris.StatusBadRequest, _urlParse.Host+"： 获取仓库信息失败")
			return
		}
		Branches, err := gitee.GetBranches()
		if err != nil {
			c.OutDataJson("", iris.StatusBadRequest, err.Error())
			return
		}
		c.OutDataJson(Branches, iris.StatusOK, strconv.Itoa(reposId))
		return
	case "github.com":
		github, err := model.NewGithub(_url)
		if err != nil {
			c.OutDataJson("", iris.StatusBadRequest, err.Error())
			return
		}
		reposId := github.GetReposId()
		if reposId == 0 {
			c.OutDataJson("", iris.StatusBadRequest, _urlParse.Host+"： 获取仓库信息失败")
			return
		}
		Branches, err := github.GetBranches()
		if err != nil {
			c.OutDataJson("", iris.StatusBadRequest, err.Error())
			return
		}
		c.OutDataJson(Branches, iris.StatusOK, strconv.Itoa(reposId))
		return
	}

	gitModel, err := model.NewUserGitlab(0, _url)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	Project := gitModel.GetGitForServerUrl(_url)
	if Project.ID == 0 {
		c.OutDataJson("", iris.StatusBadRequest, "项目获取失败，请检查账号信息中是否包含【#,!】等parse无法解析的字符")
		return
	}
	Branches := gitModel.GetBranches(Project.ID, _keywords)
	c.OutDataJson(Branches, iris.StatusOK, strconv.Itoa(Project.ID))
	return
}

type Commits struct {
	Commit *gitlab.Commit `json:"commit"`
	Avatar string         `json:"avatar"`
}

// 获取工程的提交列表
func (c *GitController) GetPublicCommitListBy(pid int) {
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	page := c.Ctx.URLParamIntDefault("page", 1)
	perPage := c.Ctx.URLParamIntDefault("perPage", 100)
	ref := c.Ctx.URLParamDefault("ref", "master")
	startTime := c.Ctx.URLParamDefault("startTime", "")
	endTime := c.Ctx.URLParamDefault("endTime", "")
	commit, _ := gitModel.GetCommits(pid, ref, page, perPage, startTime, endTime)
	// 按日期分组
	commitGroup := make(map[string]struct {
		Num     int       `json:"num"`
		Commits []Commits `json:"commits"`
	}, len(commit))
	if len(commit) > 0 {
		var wg sync.WaitGroup
		var lock sync.RWMutex
		// 取头像 go-gitlab不支持批量,并且commit接口不返回用户id
		avatar := make(map[string]string)
		// var avatar map[string]string
		for _, v := range commit {
			if _, ok := avatar[v.AuthorEmail]; ok {
				continue
			}
			user, _, _ := gitModel.Client.Users.ListUsers(&gitlab.ListUsersOptions{
				ListOptions: gitlab.ListOptions{
					Page:    1,
					PerPage: 1,
				},
				Search: gitlab.String(v.AuthorEmail),
			})
			if len(user) == 0 {
				avatar[v.AuthorEmail] = ""
				continue
			}
			lock.Lock()
			avatar[v.AuthorEmail] = user[0].AvatarURL
			lock.Unlock()
		}
		wg.Wait()
		// TODO: 待完善 获取头像 gitlab 只有根据ids获取头像的方法，根据邮箱的只能单个获取
		for _, v := range commit {
			key := v.CommittedDate.Format("2006-01-02")
			commit := commitGroup[key]
			commits := Commits{
				Commit: v,
				Avatar: avatar[v.AuthorEmail],
			}
			commit.Commits = append(commit.Commits, commits)
			commit.Num++
			commitGroup[key] = commit
		}
	}

	c.OutDataJson(commitGroup, iris.StatusOK, "success")
	return
}

// 搜索用户
func (c *GitController) GetPublicUsersList() {
	gitModel := model.NewGitlab()
	users, err := gitModel.GetNormalUsers(c.Ctx.URLParamTrim("name"))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	//排除流水线自动创建的用户devops-
	//排除开放平台自动创建的用户 _open_
	var NewUsers []*gitlab.User
	for _, v := range users {
		if !strings.Contains(v.Username, "_open_") {
			NewUsers = append(NewUsers, v)
		}
	}
	c.OutDataJson(NewUsers, iris.StatusOK, "success")
	return
}

// PostAddProjectMember 用户添加到工程中
func (c *GitController) PostAddProjectMember() {
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitUserModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 添加的用户
	member := strings.Split(c.Ctx.PostValue("member"), ",")
	pid, _ := c.Ctx.PostValueInt("pid")
	role, _ := c.Ctx.PostValueInt("role")
	expireAt := c.Ctx.PostValueTrim("deadline")
	if len(member) == 0 || pid == 0 || role == 0 {
		c.OutDataJson("", iris.StatusBadRequest, "请选择要添加的git用户")
		return
	}
	var wg sync.WaitGroup
	// var l sync.RWMutex
	for _, v := range member {
		wg.Add(1)
		accessLevel := gitlab.AccessLevelValue(role)
		go func(v string) {
			// TODO  可以更优雅的处理错误
			memberId, _ := strconv.Atoi(v)
			_, err := gitUserModel.AddProjectMember(pid, memberId, accessLevel, expireAt)
			if err != nil {
				c.Dump(err.Error())
			}
			wg.Done()
		}(v)
	}
	wg.Wait()

	c.OutDataJson("", iris.StatusOK, "添加成功")
	return
}

// 获取工程的所有成员
func (c *GitController) GetProjectMemberBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	query := c.Ctx.URLParamTrim("query")
	members, err := gitUserModel.GetProjectMember(pid, query)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 获取当前用户的gitlabUid
	userOauth := model.NewUserOauth()
	userGitInfo, err := userOauth.One(uint(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取用户的git信息失败")
		return
	}
	project, err := checkPermissionForProject(pid, uint(uid), gitUserModel)
	if err != nil {
		if project == nil {
			c.OutDataJson("", iris.StatusBadRequest, "工程信息不存在")
			return
		}

		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// //获取群组的头像和过期时间
	// c.Dump(project.ID)
	// group, _, _ := gitUserModel.Client.Groups.GetGroup(project.SharedWithGroups[0].GroupID)

	list := make([]map[string]interface{}, 0)
	existId := make([]int, len(members))
	for _, v := range members {
		member := make(map[string]interface{})
		// 用户可能存在多个群组而该项目分享到了这些群组，导致用户多次展示
		exist := util.InArrayForInt(v.ID, existId)
		if exist {
			continue
		}
		existId = append(existId, v.ID)
		// 过滤到拥有者
		if v.AccessLevel == 50 {
			continue
		}
		member["id"] = v.ID
		member["username"] = v.Username
		member["name"] = v.Name
		member["state"] = v.State
		member["expires_at"] = v.ExpiresAt
		member["access_level"] = v.AccessLevel
		member["avatar_url"] = v.AvatarURL
		if v.ID == project.Owner.ID {
			member["is_owner"] = true
		} else {
			member["is_owner"] = false
		}
		list = append(list, member)
	}
	isOwner := false
	if project.Owner.ID == int(userGitInfo.GitLabUserId) {
		isOwner = true
	}

	output := iris.Map{
		"memberList":    list,
		"isOwner":       isOwner, // 当前用户是否是工程的拥有者
		"shareGroup":    project.SharedWithGroups,
		"currentGitUid": userGitInfo.GitLabUserId,
	}
	c.OutDataJson(output, iris.StatusOK, "success")
	return
}

// 修改用户的角色和过期时间
func (c *GitController) GetChangeMemberRoleExpireBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 判断传参是否非法
	accessLevel, _ := c.Ctx.URLParamInt("accessLevel")
	gitUid, err := c.Ctx.URLParamInt("gitUid")
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "gitUid参数必须为整数")
		return
	}
	if gitUid == 0 || accessLevel == 0 {
		c.OutDataJson("", iris.StatusBadRequest, "请选择要修改的用户")
		return
	}
	expireAt := c.Ctx.URLParamDefault("expireAt", "")
	level := []int{10, 20, 30, 40}
	legal := util.InArrayForInt(accessLevel, level)
	if !legal {
		c.OutDataJson("", iris.StatusBadRequest, "异常请求:选择的角色非法")
		return
	}
	// 判断是否有操作权限
	_, hasPermissionErr := checkPermissionForProject(pid, uint(uid), gitUserModel)
	if hasPermissionErr != nil {
		c.OutDataJson("", iris.StatusBadRequest, hasPermissionErr.Error())
		return
	}
	// 改变用户在当前工程中的角色
	err = gitUserModel.EditProjectMemberRole(pid, gitUid, accessLevel, expireAt)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "修改成功")
	return
}

func (c *GitController) GetPublicDelProjectMemberBy(pid, userId int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 判断是否有操作权限
	_, hasPermissionErr := checkPermissionForProject(pid, uint(uid), gitUserModel)
	if hasPermissionErr != nil {
		c.OutDataJson("", iris.StatusBadRequest, hasPermissionErr.Error())
		return
	}
	err = gitUserModel.DeleteProjectMember(pid, userId)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "删除失败")
		return
	}

	c.OutDataJson("", iris.StatusOK, "删除成功")
	return
}

// 获取git所有群组
func (c *GitController) GetPublicAllGroups() {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	groups, err := gitUserModel.GetMyGroups()
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取群组信息失败")
		return
	}
	c.OutDataJson(groups, iris.StatusOK, "success")
	return
}

// 工程分享到群组
func (c *GitController) PostPublicShareWithGroupBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	groupId, _ := c.Ctx.PostValueInt("groupId")
	accessLevel, _ := c.Ctx.PostValueInt("accessLevel")
	expiresAt := c.Ctx.PostValueTrim("expiresAt")
	if groupId == 0 || accessLevel == 0 {
		c.OutDataJson("", iris.StatusBadRequest, "请选择要分享的群组和群组访问级别")
		return
	}
	// 权限认证，只有拥有者有操作权限
	_, hasPermissionErr := checkPermissionForProject(pid, uint(uid), gitUserModel)
	if hasPermissionErr != nil {
		c.OutDataJson("", iris.StatusBadRequest, hasPermissionErr.Error())
		return
	}
	err = gitUserModel.ShareProjectWithGroup(pid, groupId, accessLevel, expiresAt)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "分享到群组失败: "+err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "success")
	return
}

// 删除工程共享的群组
func (c *GitController) GetDeleteShareGroupBy(pid, groupId int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 权限认证，只有拥有者有操作权限
	_, hasPermissionErr := checkPermissionForProject(pid, uint(uid), gitUserModel)
	if hasPermissionErr != nil {
		c.OutDataJson("", iris.StatusBadRequest, hasPermissionErr.Error())
		return
	}
	err = gitUserModel.DeleteSharedProjectFromGroup(pid, groupId)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "删除失败:"+err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "删除成功")
	return
}

// 获取所有工程支持搜索
func (c *GitController) GetPublicProjectList() {
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitUserModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	pname := c.Ctx.URLParamTrim("name")
	projects, err := gitUserModel.GetAllProject(pname)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	c.OutDataJson(projects, iris.StatusOK, "success")
	return
}

// 从其他工程导入成员
func (c *GitController) GetImportMemberFromProject() {
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitUserModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	currentPid, _ := c.Ctx.URLParamInt("currentPid")
	importPid, _ := c.Ctx.URLParamInt("importPid")
	if currentPid == 0 || importPid == 0 {
		c.OutDataJson("", iris.StatusBadRequest, "missing params")
		return
	}
	// 判断当前操作者是否是工程的拥有者
	_, permissionErr := checkPermissionForProject(currentPid, uint(uid), gitUserModel)
	if permissionErr != nil {
		c.OutDataJson("", iris.StatusBadRequest, permissionErr.Error())
		return
	}
	// 获取导入工程的所有成员
	projectMember, err := gitUserModel.GetProjectMember(importPid, "")
	if err != nil {
		c.Dump(err.Error())
		c.OutDataJson("", iris.StatusBadRequest, "获取导入工程的成员信息失败")
		return
	}
	var wg sync.WaitGroup
	for _, v := range projectMember {
		// todo 协程内的错误处理
		wg.Add(1)
		go func(v *gitlab.ProjectMember) {
			accessLevel := gitlab.DeveloperPermissions
			_, err := gitUserModel.AddProjectMember(currentPid, v.ID, accessLevel, "")
			c.Dump(err)
			wg.Done()
		}(v)
	}
	wg.Wait()

	c.OutDataJson("", iris.StatusOK, "导入成功")
	return
}

// 判断当前用户是否是该project的拥有者
func checkPermissionForProject(pid int, uid uint, gitUserModel *model.GitUserLab) (*gitlab.Project, error) {
	// 1.获取当前工程的拥有者判断用户是否有操作权限
	ch := make(chan *gitlab.Project)
	defer close(ch)
	go func(ch chan *gitlab.Project) {
		project, err := gitUserModel.GetProjectInfo(pid)
		if err != nil {
			ch <- nil
		} else {
			ch <- project
		}
	}(ch)
	// 2.获取当前用户的git账号信息
	userOauthModel := model.NewUserOauth()
	userAuth, err := userOauthModel.One(uid)
	if err != nil {
		return nil, errors.New("获取用户git信息失败")
	}
	project := <-ch
	if project == nil {
		return nil, errors.New("获取工程信息失败")
	}
	if int(userAuth.GitLabUserId) != project.Owner.ID {
		return project, errors.New("对不起,您不是该工程的拥有者，无此权限")
	}

	return project, nil
}

// GetCommitDiffBy 提交差异
func (c *GitController) GetPublicCommitDiffBy(pid int) {
	sha := c.Ctx.URLParam("sha")
	if sha == "" {
		c.OutDataJson("", iris.StatusBadRequest, "missing commit ID")
		return
	}
	uid := int(middleware.GetTokenUId(c.Ctx))
	gitUserModel, err := model.NewUserGitlab(uid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 获取差异对比
	diff, err := gitUserModel.GetCommitDiff(pid, sha)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 获取提交信息
	commit, err := gitUserModel.GetCommitDetail(pid, sha)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取commit信息失败:"+err.Error())
		return
	}
	output := iris.Map{
		"diff":   diff,
		"commit": commit,
	}

	c.OutDataJson(output, iris.StatusOK, "success")
	return
}

// 获取分支列表 带搜索
func (c *GitController) GetPublicAllBranchesBy(pid int) {
	search := c.Ctx.URLParamDefault("name", "")
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	branches, err := gitUserModel.GetAllBranches(pid, search)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取分支失败:"+err.Error())
		return
	}
	output := make([]map[string]interface{}, len(branches))
	// 读取git信息
	project, err := gitUserModel.GetProjectInfo(pid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "读取工程信息失败:"+err.Error())
		return
	}
	if len(branches) > 0 {
		for k, v := range branches {
			tmp := make(iris.Map)
			tmp["commit"] = v.Commit
			tmp["default"] = v.Default
			tmp["developers_can_merge"] = v.DevelopersCanMerge
			tmp["developers_can_push"] = v.DevelopersCanPush
			tmp["merged"] = v.Merged
			tmp["name"] = v.Name
			tmp["protected"] = v.Protected
			tmp["download_url"] = project.WebURL + "/repository/" + v.Name + "/archive"
			output[k] = tmp
		}
	}

	c.OutDataJson(output, iris.StatusOK, "success")
	return
}

// 创建分支
func (c *GitController) PostCreateBranchBy(pid int) {
	branchName := c.Ctx.PostValueTrim("branchName")
	createFrom := c.Ctx.PostValueTrim("createFrom")
	if branchName == "" || createFrom == "" {
		c.OutDataJson("", iris.StatusBadRequest, "missing params")
		return
	}
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 权限验证，工程拥有者才能创建分支
	// TODO 具体权限后期再添加验证
	// _, permissionErr := checkPermissionForProject(pid, uint(uid), gitUserModel)
	// if permissionErr != nil {
	//    c.OutDataJson("", iris.StatusBadRequest, permissionErr.Error())
	//    return
	// }
	branch, err := gitUserModel.CreateBranch(pid, branchName, createFrom)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "创建失败:"+err.Error())
		return
	}

	c.OutDataJson(branch, iris.StatusOK, "创建成功")
	return
}

// https://docs.gitlab.com/ce/api/protected_branches.html#protect-repository-branches
// PostCreateProtectedBranchBy 创建保护分支
func (c *GitController) PostCreateProtectedBranchBy(pid int) {
	// uid := middleware.GetTokenUId(c.Ctx)
	gitModel := model.NewGitlab()

	name := c.Ctx.PostValueTrim("name")
	if name == "" {
		c.OutDataJson("", iris.StatusBadRequest, "分支名必填")
		return
	}
	opt := &gitlab.ProtectRepositoryBranchesOptions{
		Name: gitlab.String(name),
		// AllowedToPush: nil,
		// AllowedToMerge:            nil,
		// AllowedToUnprotect:        nil,
		// CodeOwnerApprovalRequired: nil,
	}
	/*
		NoPermissions         AccessLevelValue = 0
		GuestPermissions      AccessLevelValue = 10
		ReporterPermissions   AccessLevelValue = 20
		DeveloperPermissions  AccessLevelValue = 30
		MaintainerPermissions AccessLevelValue = 40   维护者
		OwnerPermissions      AccessLevelValue = 50

		// These are deprecated and should be removed in a future version
		MasterPermissions AccessLevelValue = 40
		OwnerPermission   AccessLevelValue = 50
	*/
	// 允许推送的访问权限
	if pushAccessLevel, err := c.Ctx.PostValueInt("push_access_level"); err != nil {
		if util.InArrayForInt(pushAccessLevel, []int{10, 20, 30, 40, 50}) {
			opt.PushAccessLevel = gitlab.AccessLevel(gitlab.AccessLevelValue(pushAccessLevel))
		}
	}

	// 允许合并的访问权限
	if mergeAccessLevel, err := c.Ctx.PostValueInt("merge_access_level"); err != nil {
		if util.InArrayForInt(mergeAccessLevel, []int{10, 20, 30, 40, 50}) {
			opt.MergeAccessLevel = gitlab.AccessLevel(gitlab.AccessLevelValue(mergeAccessLevel))
		}
	}

	// 允许解除保护的访问权限
	if unprotectAccessLevel, err := c.Ctx.PostValueInt("unprotect_access_level"); err != nil {
		if util.InArrayForInt(unprotectAccessLevel, []int{10, 20, 30, 40, 50}) {
			opt.UnprotectAccessLevel = gitlab.AccessLevel(gitlab.AccessLevelValue(unprotectAccessLevel))
		}
	}

	// TODO 添加允许合并的用户   待测验
	var allowMerge []*gitlab.ProtectBranchPermissionOptions
	allowMergeIds := strings.Split(c.Ctx.PostValueTrim("allowed_to_merge"), ",")
	for _, v := range allowMergeIds {
		uid, _ := strconv.Atoi(v)
		tmp := &gitlab.ProtectBranchPermissionOptions{
			UserID: gitlab.Int(uid),
		}
		allowMerge = append(allowMerge, tmp)
	}
	opt.AllowedToMerge = allowMerge

	protectedBranch, _, err := gitModel.Client.ProtectedBranches.ProtectRepositoryBranches(pid, opt)

	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "创建失败"+err.Error())
		return
	}

	c.OutDataJson(protectedBranch, iris.StatusOK, "success")
}

func (c *GitController) GetUnprotectBranchBy(id int) {
	branch := c.Ctx.URLParam("name")

	if branch == "" {
		c.OutDataJson("", iris.StatusBadRequest, "请选择要解除保护的分支")
		return
	}

	uid := middleware.GetUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	_, err = gitUserModel.Client.ProtectedBranches.UnprotectRepositoryBranches(id, branch)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "删除成功")
}

// 删除分支
func (c *GitController) GetDeleteBranchBy(pid int, branchName string) {
	if branchName == "master" {
		c.OutDataJson("", iris.StatusBadRequest, "master分支不允许删除")
		return
	}
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 只有工程拥有者才有权限删除分支
	// _, hasPermission := checkPermissionForProject(pid, uint(uid), gitUserModel)
	// if hasPermission != nil {
	//    c.OutDataJson("", iris.StatusBadRequest, hasPermission.Error())
	//    return
	// }
	err = gitUserModel.DeleteBranch(pid, branchName)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "删除失败: "+err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "删除成功")
	return
}

// 获取所有的tag
func (c *GitController) GetPublicTagListBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 校验当前用户是否在工程中
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	search := c.Ctx.URLParamDefault("search", "")
	orderBy := c.Ctx.URLParamDefault("orderBy", "updated")
	sortBy := c.Ctx.URLParamDefault("sort", "desc")
	tags, err := gitUserModel.GetAllTag(pid, orderBy, sortBy, search)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取标签失败: "+err.Error())
		return
	}
	// 获取工程信息
	project, err := gitUserModel.GetProjectInfo(pid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取工程信息失败:"+err.Error())
		return
	}
	output := make([]iris.Map, len(tags))
	if len(tags) > 0 {
		for k, v := range tags {
			tmp := iris.Map{}
			tmp["commit"] = v.Commit
			tmp["message"] = v.Message
			tmp["name"] = v.Name
			tmp["release"] = v.Release
			tmp["download_url"] = project.WebURL + "/repository/" + v.Name + "/archive"
			output[k] = tmp
		}
	}

	c.OutDataJson(output, iris.StatusOK, "success")
	return
}

// 创建标签
func (c *GitController) PostCreateTagBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	tagName := c.Ctx.PostValueTrim("tagName")
	if tagName == "" {
		c.OutDataJson("", iris.StatusBadRequest, "请填写标签名称")
		return
	}
	createFrom := c.Ctx.PostValueDefault("createFrom", "master")
	message := html.EscapeString(c.Ctx.PostValue("message"))
	remark := html.EscapeString(c.Ctx.PostValue("remark"))
	tag, err := gitUserModel.CreateTag(pid, tagName, createFrom, message, remark)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "创建失败"+err.Error())
		return
	}

	c.OutDataJson(tag, iris.StatusOK, "success")
	return
}

// 编辑标签
func (c *GitController) PostEditTagRemarkBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 校验当前用户是否在工程中
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	remark := c.Ctx.PostValueDefault("remark", "")
	tag := html.EscapeString(c.Ctx.PostValue("tag"))
	if tag == "" {
		c.OutDataJson("", iris.StatusBadRequest, "请选择要修改的tag")
		return
	}
	note, err := gitUserModel.EditTag(pid, tag, remark)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "更新失败:"+err.Error())
		return
	}

	c.OutDataJson(note, iris.StatusOK, "更新成功")
	return
}

// 删除标签
func (c *GitController) GetDeleteTagBy(pid int, tag string) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 校验当前用户是否在工程中
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	err = gitUserModel.DeleteTag(pid, tag)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "删除成功")
	return
}

// 删除已合并的分支
func (c *GitController) GetDeleteMergedBranchBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 只有工程拥有者才有权限删除
	// _, hasPermission := checkPermissionForProject(pid, uint(uid), gitUserModel)
	// if hasPermission != nil {
	//    c.OutDataJson("", iris.StatusBadRequest, hasPermission.Error())
	//    return
	// }
	err = gitUserModel.DeleteMergedBranch(pid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "删除失败:"+err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "success")
	return
}

// 新增webhook
func (c *GitController) PostAddWebhook() {
	hookUrl := html.EscapeString(c.Ctx.PostValueTrim("url"))
	token := html.EscapeString(c.Ctx.PostValueTrim("token"))
	if hookUrl == "" || token == "" {
		c.OutDataJson("", iris.StatusBadRequest, "请填写链接URL和令牌")
		return
	}
	opt := gitlab.AddHookOptions{}
	opt.URL = gitlab.String(hookUrl)
	opt.Token = gitlab.String(token)
	if push, err := c.Ctx.PostValueBool("hookPush"); err != nil {
		opt.PushEvents = gitlab.Bool(push)
	}
	if tag, err := c.Ctx.PostValueBool("hookTag"); err != nil {
		opt.TagPushEvents = gitlab.Bool(tag)
	}
	if merge, err := c.Ctx.PostValueBool("hookMerge"); err != nil {
		opt.MergeRequestsEvents = gitlab.Bool(merge)
	}
	if repository, err := c.Ctx.PostValueBool("hookRepositoryUpdate"); err != nil {
		opt.RepositoryUpdateEvents = gitlab.Bool(repository)
	}
	if ssl, err := c.Ctx.PostValueBool("ssl"); err != nil {
		opt.EnableSSLVerification = gitlab.Bool(ssl)
	}
	gitModel := model.NewGitlab()
	err := gitModel.AddWebhook(opt)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "新增hook失败:"+err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "新增成功")
	return
}

// 合并请求列表
func (c *GitController) GetPublicMergeRequestListBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	state := html.EscapeString(c.Ctx.URLParamDefault("state", "opened"))
	exist := util.InArray(state, []string{"opened", "closed", "merged", "all"})
	if !exist {
		c.OutDataJson("", iris.StatusBadRequest, "非法请求: 状态参数异常")
		return
	}
	search := html.EscapeString(c.Ctx.URLParamTrim("search"))
	mergeRequest, err := gitUserModel.GetProjectMergeRequest(pid, state, search)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取数据失败:"+err.Error())
		return
	}

	c.OutDataJson(mergeRequest, iris.StatusOK, "success")
	return
}

// 获取合并请求的提交记录
func (c *GitController) PostPublicMergeCommitsListBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	page := c.Ctx.PostValueIntDefault("page", 1)
	iid, err := c.Ctx.PostValueInt("iid")
	if err != nil || iid == 0 {
		c.OutDataJson("", iris.StatusBadRequest, "iid params unusual")
		return
	}
	commits, err := gitUserModel.MergeRequestCommit(pid, iid, page)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}

	c.OutDataJson(commits, iris.StatusOK, "success")
	return
}

func (c *GitController) PostPublicCreateMergeBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	removeSourceBranch, err := c.Ctx.PostValueBool("removeSourceBranch")
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	squash, err := c.Ctx.PostValueBool("squash")
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// labels := c.Ctx.PostValueTrim("labels")
	opt := &gitlab.CreateMergeRequestOptions{
		Title:           gitlab.String(c.Ctx.PostValueTrim("title")),
		Description:     gitlab.String(c.Ctx.PostValueDefault("desc", "")),
		SourceBranch:    gitlab.String(c.Ctx.PostValueTrim("sourceBranch")),
		TargetBranch:    gitlab.String(c.Ctx.PostValueTrim("targetBranch")),
		Labels:          &gitlab.Labels{c.Ctx.PostValueTrim("labels")},
		TargetProjectID: gitlab.Int(c.Ctx.PostValueIntDefault("targetPid", pid)),
		// MilestoneID:        nil,   //todo  里程碑暂不支持
		RemoveSourceBranch: gitlab.Bool(removeSourceBranch),
		Squash:             gitlab.Bool(squash),
		AllowCollaboration: gitlab.Bool(true), // 允许可以合并到目标分支的成员提交
	}
	if opt.Title == nil || opt.SourceBranch == nil || opt.TargetBranch == nil {
		c.OutDataJson("", iris.StatusBadRequest, "标题，合并分支参数必填")
		return
	}
	assigneeId := c.Ctx.PostValueTrim("assigneeId")
	if assigneeId != "" {
		var assigneeArr []int
		for _, v := range strings.Split(assigneeId, ",") {
			assInt, _ := strconv.Atoi(v)
			assigneeArr = append(assigneeArr, assInt)
		}
		opt.AssigneeIDs = assigneeArr
	}

	mr, err := gitUserModel.CreateMergeRequet(pid, opt)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "合并请求失败:"+err.Error())
		return
	}
	c.OutDataJson(mr, iris.StatusOK, "合并成功")
	return
}

func (c *GitController) GetDeleteMergeRequestBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	iidStr := c.Ctx.URLParamTrim("iid")
	if iidStr == "" {
		c.OutDataJson("", iris.StatusBadRequest, "请选择要删除的合并请求")
		return
	}
	iidArr := strings.Split(iidStr, ",")
	var wg sync.WaitGroup
	ch := make(chan error, len(iidArr))
	defer close(ch)
	for _, v := range iidArr {
		wg.Add(1)
		go func(v string) {
			iid, _ := strconv.Atoi(v)
			err := gitUserModel.DeleteMergeRequest(pid, iid)
			if err != nil {
				ch <- errors.New(fmt.Sprintf("删除编号为%d的合并失败: %s \n", iid, err.Error()))
			} else {
				ch <- nil
			}
			wg.Done()
		}(v)
	}
	wg.Wait()
	var errMsg string
	for i := 0; i < len(iidArr); i++ {
		err := <-ch
		if err != nil {
			errMsg += err.Error()
		}
	}
	if errMsg != "" {
		c.OutDataJson("", iris.StatusBadRequest, errMsg)
		return
	}

	c.OutDataJson("", iris.StatusOK, "删除成功")
	return
}

func (c *GitController) PostEditMergeRequestBy(pid int) {
	mergeIds := strings.Split(c.Ctx.PostValueTrim("mergeIds"), ",")
	if len(mergeIds) <= 0 {
		c.OutDataJson("", iris.StatusBadRequest, "请选择要修改的合并请求")
		return
	}
	stateEvent := c.Ctx.PostValueTrim("state_event")
	if stateEvent != "" {
		valid := util.InArray(stateEvent, []string{"close", "reopen"})
		if !valid {
			c.OutDataJson("", iris.StatusBadRequest, "非法请求:状态参数异常")
			return
		}
	}
	assigneeId := c.Ctx.PostValueTrim("assigneeId")
	labels := c.Ctx.PostValueTrim("labels")
	if labels == "" && stateEvent == "" && assigneeId == "" {
		c.OutDataJson("", iris.StatusBadRequest, "请选择要更新的数据")
		return
	}

	opt := &gitlab.UpdateMergeRequestOptions{
		AssigneeIDs: nil,
		Labels:      nil,
		StateEvent:  nil,
	}
	if assigneeId != "" {
		var assigneeArr []int
		for _, v := range strings.Split(assigneeId, ",") {
			assInt, _ := strconv.Atoi(v)
			assigneeArr = append(assigneeArr, assInt)
		}
		opt.AssigneeIDs = assigneeArr
	}
	if labels != "" {
		opt.Labels = &gitlab.Labels{labels}
	}
	if stateEvent != "" {
		opt.StateEvent = gitlab.String(stateEvent)
	}

	var wg sync.WaitGroup
	ch := make(chan error, len(mergeIds))
	defer close(ch)
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	for _, v := range mergeIds {
		mergeId, _ := strconv.Atoi(v)
		wg.Add(1)
		go func(ch chan error) {
			_, err := gitUserModel.EditMergeRequest(pid, mergeId, opt)
			if err != nil {
				ch <- errors.New(fmt.Sprintf("编辑编号为%d的合并失败: %s \n", mergeId, err.Error()))
			} else {
				ch <- nil
			}
			wg.Done()
		}(ch)
	}
	wg.Wait()
	var errMsg string
	for i := 0; i < len(mergeIds); i++ {
		err := <-ch
		if err != nil {
			errMsg += err.Error()
		}
	}
	if errMsg != "" {
		c.OutDataJson("", iris.StatusBadRequest, errMsg)
		return
	}

	c.OutDataJson("", iris.StatusOK, "编辑成功")
	return
}

// 获取工程的标签 没有则创建默认的
func (c *GitController) GetPublicProjectLabelsBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	labels, err := gitUserModel.GetProjectLabels(pid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取labels失败:"+err.Error())
		return
	}
	if len(labels) > 0 {
		c.OutDataJson(labels, iris.StatusOK, "success")
		return
	}
	// 没有则创建一组默认的标签
	defaultLabels := []map[string]string{
		{"name": "bug", "color": "#d9534f", "desc": ""},
		{"name": "confirmed", "color": "#d9534f", "desc": ""},
		{"name": "critical", "color": "#d9534f", "desc": ""},
		{"name": "discussion", "color": "#428bca", "desc": ""},
		{"name": "documentation", "color": "#f0ad4e", "desc": ""},
		{"name": "enhancement", "color": "#5cb85c", "desc": ""},
		{"name": "suggestion", "color": "#428bca", "desc": ""},
		{"name": "support", "color": "#f0ad4e", "desc": ""},
	}
	var wg sync.WaitGroup
	var l sync.RWMutex
	ch := make(chan error, len(defaultLabels))
	defer close(ch)
	for _, v := range defaultLabels {
		wg.Add(1)
		go func(v map[string]string, ch chan error) {
			l.RLock()
			name, color, desc := v["name"], v["color"], v["desc"]
			l.RUnlock()
			_, err := gitUserModel.CreateLabelsForProject(pid, name, color, desc)
			if err != nil {
				ch <- errors.New(fmt.Sprintf("创建默认标签%s失败,", name))
			} else {
				ch <- nil
			}
			wg.Done()
		}(v, ch)
	}
	wg.Wait()
	var errMsg string
	for i := 0; i < len(defaultLabels); i++ {
		err = <-ch
		if err != nil {
			errMsg += err.Error()
		}
	}

	if errMsg != "" {
		c.OutDataJson("", iris.StatusBadRequest, errMsg)
		return
	}
	labelArr, err := gitUserModel.GetProjectLabels(pid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取labels失败:"+err.Error())
		return
	}
	c.OutDataJson(labelArr, iris.StatusOK, "success")
	return
}

// wiki目录列表
func (c *GitController) GetPublicWikiListBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	wikis, err := gitUserModel.GetWikiList(pid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取数据失败:"+err.Error())
		return
	}
	// 获取wiki仓库地址
	project, err := gitUserModel.GetProjectInfo(pid)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取工程信息失败:"+err.Error())
		return
	}
	httpRepo := strings.Replace(project.HTTPURLToRepo, ".git", ".wiki.git", 1)
	sshRepo := strings.Replace(project.SSHURLToRepo, ".git", ".wiki.git", 1)
	output := iris.Map{
		"wiki": wikis,
		"http": httpRepo,
		"ssh":  sshRepo,
	}

	c.OutDataJson(output, iris.StatusOK, "success")
	return
}

// wiki详情
func (c GitController) GetPublicWikiDetailBy(pid int) {
	slug := c.Ctx.URLParamTrim("slug")
	if slug == "" {
		c.OutDataJson("", iris.StatusBadRequest, "缺少页面标识")
		return
	}
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	wiki, err := gitUserModel.GetWikiContent(pid, slug)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取内容失败:"+err.Error())
		return
	}

	c.OutDataJson(wiki, iris.StatusOK, "success")
	return
}

// 创建wiki
func (c *GitController) PostCreateWikiBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 判断用户是否在工程中，如果不在无法创建
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	content := c.Ctx.PostValueTrim("content")
	title := html.EscapeString(c.Ctx.PostValueTrim("title"))
	if content == "" || title == "" {
		c.OutDataJson("", iris.StatusBadRequest, "请填写标题和文档内容")
		return
	}
	wiki, err := gitUserModel.CreateWiki(pid, content, title)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "创建失败:"+err.Error())
		return
	}

	c.OutDataJson(wiki, iris.StatusOK, "创建成功")
	return
}

// 编辑wiki
func (c *GitController) PostEditWikiBy(pid int) {
	slug := c.Ctx.PostValueTrim("slug")
	if slug == "" {
		c.OutDataJson("", iris.StatusBadRequest, "缺少页面标识")
		return
	}
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 判断用户是否在工程中，如果不在无法删除
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	content := c.Ctx.PostValueTrim("content")
	title := html.EscapeString(c.Ctx.PostValueTrim("title"))
	if content == "" || title == "" {
		c.OutDataJson("", iris.StatusBadRequest, "请填写标题和文档内容")
		return
	}
	wiki, err := gitUserModel.EditWiki(pid, slug, content, title)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "编辑失败:"+err.Error())
		return
	}

	c.OutDataJson(wiki, iris.StatusOK, "编辑成功")
	return
}

// 删除wiki
func (c *GitController) GetDeleteWikiBy(pid int) {
	slug := c.Ctx.URLParamTrim("slug")
	if slug == "" {
		c.OutDataJson("", iris.StatusBadRequest, "缺少页面标识")
		return
	}
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	// 判断用户是否在工程中，如果不在无法删除
	_, err = gitUserModel.CheckUserIsInProject(pid, int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	err = gitUserModel.DeleteWiki(pid, slug)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "删除wiki失败:"+err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "删除成功")
	return
}

// GetPublicSshkeys 获取ssh keys
func (c *GitController) GetPublicSshkeys() {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	SSHKeys, err := gitUserModel.ListSSHKeys()
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取ssh key失败:"+err.Error())
		return
	}

	c.OutDataJson(SSHKeys, iris.StatusOK, "success")
	return
}

// PostAddSshkey 添加
func (c *GitController) PostPublicAddSshkey() {
	title := html.EscapeString(c.Ctx.PostValueTrim("title"))
	key := html.EscapeString(c.Ctx.PostValueTrim("key"))
	if title == "" || key == "" {
		c.OutDataJson("", iris.StatusBadRequest, "missing params")
		return
	}
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	SSHKey, err := gitUserModel.AddSSHKey(title, key)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "添加ssh key失败:"+err.Error())
		return
	}

	c.OutDataJson(SSHKey, iris.StatusOK, "success")
	return
}

// GetDeleteSshkeyBy 删除ssh key
func (c *GitController) GetPublicDeleteSshkeyBy(id int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	err = gitUserModel.DeleteSSHKey(id)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "删除失败:"+err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "删除成功")
	return
}

// 获取群组列表
func (c *GitController) GetPublicGroupList() {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	owned, err := c.Ctx.URLParamBool("owned")
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	search := c.Ctx.URLParamTrim("search")
	groups, err := gitUserModel.ListAllGroup(owned, search)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取群组信息失败:"+err.Error())
		return
	}
	output := iris.Map{
		"list":      groups,
		"gitServer": ymlgo.NewConfigSysBase().GitLabServer,
	}

	c.OutDataJson(output, iris.StatusOK, "success")
	return
}

// PostCreateGroup  创建群组
func (c *GitController) PostCreateGroup() {
	name := html.EscapeString(c.Ctx.PostValueTrim("name"))
	if name == "" {
		c.OutDataJson("", iris.StatusBadRequest, "群组名称必填")
		return
	}
	SysConfig := ymlgo.NewConfigSysBase()
	path := html.EscapeString(c.Ctx.PostValueDefault("path", SysConfig.GitLabServer+name))
	visibility := c.Ctx.PostValueDefault("visibility", "private")
	valid := util.InArray(visibility, []string{"private", "internal", "public"})
	// 是否允许上传大文件
	if !valid {
		c.OutDataJson("", iris.StatusBadRequest, "非法请求:可见性参数异常")
		return
	}
	lfsEnabled, err := c.Ctx.PostValueBool("lfsEnabled")
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "参数异常")
		return
	}
	opt := &gitlab.CreateGroupOptions{
		Name:        gitlab.String(name),
		Path:        gitlab.String(path),
		Description: gitlab.String(html.EscapeString(c.Ctx.PostValueDefault("desc", ""))),
		Visibility:  gitlab.Visibility(gitlab.VisibilityValue(visibility)), // 可见性 private, internal, or public
		LFSEnabled:  gitlab.Bool(lfsEnabled),                               // 是否允许上传大文件
	}
	if parentId := c.Ctx.PostValue("parentId"); parentId != "" {
		parentIdInt, err := strconv.Atoi(parentId)
		if err != nil {
			c.OutDataJson("", iris.StatusBadRequest, err.Error())
			return
		}
		opt.ParentID = gitlab.Int(parentIdInt)
	}
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, _ := model.NewUserGitlab(int(uid))
	group, err := gitUserModel.CreateGroup(opt)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "创建群组失败:"+err.Error())
		return
	}

	c.OutDataJson(group, iris.StatusOK, "创建成功")
	return
}

// GetDeleteGroupBy  删除群组
func (c *GitController) GetDeleteGroupBy(groupId int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	if err := gitUserModel.DeleteGroup(groupId); err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "删除群组失败:"+err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "删除成功")
	return
}

func (c *GitController) PostEditGroupBy(groupId int) {
	// 入参校验
	name := c.Ctx.PostValueTrim("name")
	desc := c.Ctx.PostValueTrim("desc")
	visibility := c.Ctx.PostValueTrim("visibility")
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	if _, err := gitUserModel.EditGroup(groupId, name, desc, gitlab.VisibilityValue(visibility)); err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "编辑群组失败:"+err.Error())
		return
	}

	c.OutDataJson("", iris.StatusOK, "编辑成功")
	return
}

// 获取群组详情
func (c *GitController) GetGroupDetailBy(groupId int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitUserModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	detail, err := gitUserModel.GroupDetail(groupId)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取详情失败:"+err.Error())
		return
	}
	// 获取子组
	subGroups, err := gitUserModel.GetSubGroups(groupId)
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, "获取子组信息失败:"+err.Error())
		return
	}
	output := iris.Map{
		"detail":    detail,
		"subGroups": subGroups,
		"gitServer": ymlgo.NewConfigSysBase().GitLabServer,
	}
	c.OutDataJson(output, iris.StatusOK, "success")
	return
}

/**
获取所有的分支和tag
*/
func (c *GitController) GetPublicBranchTagBy(pid int) {
	uid := middleware.GetTokenUId(c.Ctx)
	gitModel, err := model.NewUserGitlab(int(uid))
	if err != nil {
		c.OutDataJson("", iris.StatusBadRequest, err.Error())
		return
	}
	output := iris.Map{
		"branches": gitModel.GetBranches(pid, ""),
		"tags":     gitModel.GetTags(pid),
	}

	c.OutDataJson(output, iris.StatusOK, "success")
	return
}
